#pragma once

#include <ioxx_button_trigger.hpp>

#include "app.hpp"
#include "between_face_common.hpp"
#include "menu.hpp"
#include "modbus_client.hpp"
#include "oled.hpp"
#include "storage.hpp"


TimeType task_scan_button();

void reset_buttons();

void reset_button_event();

void init_buttons();


class Blinker {
    bool _blinking = false;
    bool _blink_phase = false;

    TimeCycle _blink_tc;

   public:
    void start_blink() {
        _blink_tc.reset();
        _blinking = true;
        _blink_phase = false;
        show_ask("-=");
    }

    void stop_blink() {
        show_ask(nullptr);
        _blinking = false;
    }

    /**
     * @brief
     *
     * @return true   显示缓冲区已被修改
     * @return false
     */
    bool blink() {
        if (_blinking) {
            if (_blink_tc.cycle(300)) {
                if (_blink_phase) {
                    show_ask("-=");
                }
                else {
                    show_ask("=-");
                }
                _blink_phase = !_blink_phase;
                return true;
            }
        }
        return false;
    }
};


struct Count {
    uint16_t m;
    uint16_t mm;
};


extern ioxx::ButtonTrigger<> button_up;
extern ioxx::ButtonTrigger<> button_down;
extern ioxx::ButtonTrigger<> button_left;
extern ioxx::ButtonTrigger<> button_right;
extern ioxx::ButtonTrigger<> button_ok;


extern Blinker bkr;


constexpr uint8_t MENU_ITEM_COUNT = 13;
constexpr uint8_t MENU_ROW_COUNT = 3;

extern MenuItem menu_items[MENU_ITEM_COUNT];


constexpr ConstantStrArray CONNECTION_METHOD_LIST = {"RS485", "LORA"};  // 连接方式选项

constexpr ConstantStrArray BAUD_LIST = {"2400", "4800", "9600", "19200", "38400", "115200"};

constexpr uint32_t BAUD_NUMBER_LIST[] = {2400, 4800, 9600, 19200, 38400, 115200};

constexpr ConstantStrArray UNIT_LIST = {"毫米", "厘米", "分米", "米"};

constexpr uint16_t UNIT_NUMBER_LIST[] = {1, 10, 100, 1000};

constexpr uint8_t unit_number_to_index(uint16_t u) {
    switch (u) {
        case 1:
            return 0;
        case 10:
            return 1;
        case 100:
            return 2;
        case 1000:
            return 3;
        default:
            return 0;
    }
}


constexpr ConstantStrArray HELP_TEXT_LIST = {
    "更改参数将",
    "实时写入从机,",
    "错误的参数",
    "会使从机工作",
    "异常或通信",
    "失败"};

constexpr ConstantStrArray INPUT_METHOD_LIST = {
    "点OK打开设定,",
    "长按关闭;",
    "通信成功时,",
    "点OK关闭,",
    "通信失败时",
    "点OK重试;",
    "如果通信失败",
    "检查波特率",
    "和从机地址",
    "等参数"};


constexpr uint8_t MENU_INDEX_ADDRESS = 0;
constexpr uint8_t MENU_INDEX_AUTO_ADDRESS = 1;
constexpr uint8_t MENU_INDEX_CONNECTION = 2;
constexpr uint8_t MENU_INDEX_BAUD = 3;
constexpr uint8_t MENU_INDEX_CHANNEL = 4;
constexpr uint8_t MENU_INDEX_PERIOD = 5;
constexpr uint8_t MENU_INDEX_DEVICE_PARAM = 7;

constexpr uint8_t MENU_INDEX_PARAM_ADDRESS = 8;
constexpr uint8_t MENU_INDEX_PARAM_OFFSET = 9;
constexpr uint8_t MENU_INDEX_PARAM_连测间隔 = 10;
constexpr uint8_t MENU_INDEX_PARAM_BAUD = 11;
constexpr uint8_t MENU_INDEX_PARAM_UNIT = 12;

constexpr uint8_t MENU_INDEX_LOAD = 0xff;


inline void init_menu_item() {
    // 初始化菜单项为默认值
    menu_items[0]
        .item_label("从机地址")
        .as_unsigned(1, 3);  // 从机地址默认值 == 1

    menu_items[1]
        .item_label("自动取址")
        .as_no_value();

    menu_items[2]
        .item_label("连接方式")
        .as_option(CONNECTION_METHOD_LIST);

    menu_items[3]
        .item_label("波特率")
        .as_option(BAUD_LIST);

    menu_items[4]
        .item_label("频道")
        .as_unsigned(1, 2);

    menu_items[5]
        .item_label("连测周期")
        .as_unsigned(5, 2, 2);

    menu_items[6]
        .item_label("操作方法V01")
        .as_help(INPUT_METHOD_LIST);

    menu_items[7]
        .item_label("以下为从机参数")
        .as_help(HELP_TEXT_LIST);

    // 把寄存器地址存在菜单项的id 里
    menu_items[8]
        .item_label("地址")
        .item_id(2)
        .as_unsigned(1, 3);

    menu_items[9]
        .item_label("偏置")
        .item_id(4)
        .as_signed(105, 3);

    menu_items[10]
        .item_label("连测间隔")
        .item_id(5)
        .as_unsigned(0, 3);

    menu_items[11]
        .item_label("波特率")
        .item_id(6)
        .as_option(BAUD_LIST);

    // 单位选项是预留的，没用
    menu_items[12]
        .item_label("单位")
        .item_id(7)
        .as_option(UNIT_LIST);
}


constexpr uint8_t SAVED_ITEM_COUNT = 6;


/**
 * @brief 初始化菜单项，读取存储的数据
 *
 */
inline void setup_menu_item() {
    init_menu_item();
    load_from_storage(menu_items, SAVED_ITEM_COUNT);
}


inline uint16_t slave_address() {
    return menu_items[MENU_INDEX_ADDRESS].unsigned_value();  // 从机地址在第一个菜单项
}


// set_menu_*** 表示仅设置 *** 菜单项的显示内容，而不是设置从机的参数
inline void set_menu_slave_address(uint16_t addr) {
    menu_items[MENU_INDEX_ADDRESS].data.u = addr;
    menu_items[MENU_INDEX_PARAM_ADDRESS].data.u = addr;
}

inline void set_menu_baud_index(uint16_t b) {
    menu_items[MENU_INDEX_BAUD].index = b;
}

// set_menu_param_*** 表示仅设置关于从机参数 *** 的菜单项的显示内容，不写入从机
inline void set_menu_param_offset(int16_t offset) {
    menu_items[MENU_INDEX_PARAM_OFFSET].data.s = offset;
}

inline void set_menu_param_连测间隔(uint16_t t) {
    menu_items[MENU_INDEX_PARAM_连测间隔].data.u = t;
}

inline void set_menu_param_baud_index(uint16_t b) {
    menu_items[MENU_INDEX_PARAM_BAUD].index = b;
}

inline void set_menu_param_unit_index(uint16_t u) {
    menu_items[MENU_INDEX_PARAM_UNIT].index = u;
}

inline uint16_t 连测周期() {
    return menu_items[5].unsigned_value();
}

inline uint32_t baudrate() {
    auto index = menu_items[MENU_INDEX_BAUD].index;
    return BAUD_NUMBER_LIST[index];
}


inline void put_slave_address(char prefix = 0) {
    if (prefix == 0) {
        prefix = '#';
        if (menu_items[MENU_INDEX_CONNECTION].index == 1) {
            // 如果用LORA 连接
            prefix = '@';
        }
    }

    show_slave_address(slave_address(), prefix);
}


inline void init_modbus_client_by_menu() {
    auto baud = baudrate();
    init_modbus_client(baud);
}


constexpr int NAVIGATION_LEFT = 1;
constexpr int NAVIGATION_RIGHT = 2;
constexpr int NAVIGATION_RETURN_OK = 3;
constexpr int NAVIGATION_RETURN_FAIL = 4;
